package com.netty.handler;

import com.netty.CIMWebSocketRequestHandler;
import com.netty.constant.Constants;
import com.netty.model.Ping;
import com.netty.model.SentBody;
import com.netty.model.proto.SentBodyProto;
import com.netty.utils.Md5Utils;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author zl
 * @version 1.0
 * @date 2021/9/15 9:32
 */
@ChannelHandler.Sharable
public class ImWebScoketServerHandler extends SimpleChannelInboundHandler<SentBodyProto.Model> {

    private Logger logger = LoggerFactory.getLogger(getClass());

    private CIMWebSocketRequestHandler cimRequestHandler;

    public ImWebScoketServerHandler(CIMWebSocketRequestHandler cimRequestHandler) {
        this.cimRequestHandler = cimRequestHandler;
    }

    @Override
    public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
        logger.info(">>>>>>>>>>>>>>>>>>>>>>channel注册了<<<<<<<<<<<<<<<<<<<<<<");
    }

    @Override
    public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
        logger.info(">>>>>>>>>>>>>>>>>>>>>>channel移除了<<<<<<<<<<<<<<<<<<<<<<");
        if (ctx.channel().attr(Constants.SessionConfig.UID) == null) {
            return;
        }
        Constants.executorService.submit(new Runnable() {
            @Override
            public void run() {
                cimRequestHandler.channelUnregistered(ctx.channel());
            }
        });
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        ctx.channel().attr(Constants.SessionConfig.ID).set(Md5Utils.shortMd5(ctx.channel().id().asLongText()));
        ctx.channel().attr(Constants.SessionConfig.CHANNEL).set(Constants.ImserverConfig.WEBSOCKET);
    }

    @Override
    public void channelRead0(ChannelHandlerContext ctx, SentBodyProto.Model msg) throws Exception {
        Constants.executorService.submit(new Runnable() {
            @Override
            public void run() {
                cimRequestHandler.channelRead0(ctx.channel(), msg);
            }
        });
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) {
        if (!(evt instanceof IdleStateEvent)) {
            return;
        }

        IdleStateEvent idleEvent = (IdleStateEvent) evt;

        String uid = ctx.channel().attr(Constants.SessionConfig.UID).get();

        /*
         * 关闭未认证的连接
         */
        if (idleEvent.state() == IdleState.WRITER_IDLE && uid == null) {
            ctx.close();
            return;
        }

        /*
         * 已经认证的连接发送心跳请求
         */
        if (idleEvent.state() == IdleState.WRITER_IDLE && uid != null) {

            Integer pingCount = ctx.channel().attr(Constants.SessionConfig.PING_COUNT).get();
            ctx.channel().attr(Constants.SessionConfig.PING_COUNT).set(pingCount == null ? 1 : pingCount + 1);
            ctx.channel().writeAndFlush(Ping.getInstance());

            return;
        }

        /*
         * 如果心跳请求发出30秒内没收到响应，则关闭连接
         */
        Integer pingCount = ctx.channel().attr(Constants.SessionConfig.PING_COUNT).get();
        if (idleEvent.state() == IdleState.READER_IDLE && pingCount != null && pingCount >= Constants.ImserverConfig.PING_TIME_OUT) {
            ctx.close();
            logger.info("{} pong timeout.", ctx.channel());
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        logger.info("channel 捕获到异常了，关闭了{}", cause);
        super.exceptionCaught(ctx, cause);
        cimRequestHandler.channelUnregistered(ctx.channel());
    }

}
